﻿using System;
using CommunicationProtocol.dto.command;
using Microsoft.Extensions.Logging;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using monoClient.communication;
using monoClient.utils;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using monoClient.renderer;
using CommandExecutor = monoClient.renderer.CommandExecutor;

namespace monoClient
{
    public class Game1 : Game
    {
        private GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;

        private SyncServerGamingDataTask syncServerGamingDataTask;

        private ConcurrentDictionary<CommandExecutor,object> commandExecutors;

        
        Vector2 ballPosition;

        float ballSpeed;

        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;

        }

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            ballPosition = new Vector2(
                _graphics.PreferredBackBufferWidth/2, 
                _graphics.PreferredBackBufferHeight/2
                );

            ballSpeed = 100f;


            base.Initialize();
        }

        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here

            commandExecutors = new ConcurrentDictionary<CommandExecutor,object>(); ;

            // 添加背景
            commandExecutors.TryAdd( new BackGroundRenderer(Content, _graphics),null);

            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

            syncServerGamingDataTask = new SyncServerGamingDataTask(
                "localhost",
                18899,
                commandExecutors,
                cancellationTokenSource.Token
                );

            ImageUtils.loadCache(Content);

            Task.Factory.StartNew(async () =>
                {
                    await syncServerGamingDataTask.run();
                },
                cancellationTokenSource.Token,
                // 告诉调度器此线程会长时间运行
                // 调度器为其分配专门的线程，
                // 1、避免本任务长时间占用工作线程，增大短时间任务的响应事件
                // 2、有更多的事件分片，避免此任务长时间占用处理器，让其他任务没有时间运行
                TaskCreationOptions.LongRunning,
                TaskScheduler.Default
            ).ContinueWith(task =>
            {
                AggregateException aggregateException = task.Exception.Flatten();
                
                aggregateException.Handle(exception =>
                {
                    
                    Debug.WriteLine("异常退出"+ exception.Message);

                    return false;
                });
                
            },TaskContinuationOptions.OnlyOnFaulted);
        }

        private MouseState oldMouseState;
        
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            // TODO: Add your update logic here
            var kstate = Keyboard.GetState();
            MouseState mouseState = Mouse.GetState();
            if (kstate.IsKeyDown(Keys.Up))
            {
                ballPosition.Y -= ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            }

            if (kstate.IsKeyDown(Keys.Down))
            {
                ballPosition.Y += ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            }

            if (kstate.IsKeyDown(Keys.Left))
            {
                ballPosition.X -= ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            }

            if (kstate.IsKeyDown(Keys.Right))
            {
                ballPosition.X += ballSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            }


            foreach (CommandExecutor executor in commandExecutors.Keys) {

                executor.Update(gameTime, mouseState,oldMouseState);
            }

            oldMouseState = mouseState;

            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

           
            _spriteBatch.Begin();

            
            
            foreach (var commandExecutor in commandExecutors.Keys)
            {
                commandExecutor.Draw(gameTime, _spriteBatch);
            }
           
            

            _spriteBatch.End();
         
            

            base.Draw(gameTime);
        }
    }
}
